package com.song.tools.songtest.trigger.sysuser;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollUtil;
import com.song.tools.core.exception.BusinessException;
import com.song.tools.core.exception.ExceptionCodeEnum;
import com.song.tools.core.util.ObjectUtils;
import com.song.tools.core.util.UserUtil;
import com.song.tools.log.operatelog.annotation.OLog;
import com.song.tools.log.operatelog.core.LogRecordContext;
import com.song.tools.log.operatelog.enums.ActionTypeEnum;
import com.song.tools.log.operatelog.enums.ModuleEnum;
import com.song.tools.mvc.validator.StrNotBlankValidator;
import com.song.tools.mvc.validator.ValidationException;
import com.song.tools.mvc.validator.ValidationResult;
import com.song.tools.mvc.validator.ValidatorChain;
import com.song.tools.songtest.beans.bo.SysRoleBo;
import com.song.tools.songtest.beans.bo.SysRoleUserBo;
import com.song.tools.songtest.beans.bo.SysUserBo;
import com.song.tools.songtest.beans.query.SysRoleUserQuery;
import com.song.tools.songtest.beans.query.SysUserQuery;
import com.song.tools.songtest.beans.request.SysUserLoginRequest;
import com.song.tools.songtest.beans.response.SysUserLoginResponse;
import com.song.tools.songtest.beans.vo.RoleVO;
import com.song.tools.songtest.beans.vo.UserVO;
import com.song.tools.songtest.component.CipherComponent;
import com.song.tools.songtest.constants.StatusEnum;
import com.song.tools.songtest.constants.TriggerTypeEnum;
import com.song.tools.songtest.manager.SysRoleManager;
import com.song.tools.songtest.manager.SysRoleUserManager;
import com.song.tools.songtest.manager.SysUserManager;
import com.song.tools.trigger.AbstractTriggerTemplate;
import com.song.tools.trigger.TriggerContext;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.List;

/**
 * 用户登录触发器
 *
 * @author song tools
 * @since 2024-07-19
 */
@Slf4j
@Component
public class UserLoginTrigger extends AbstractTriggerTemplate<SysUserLoginRequest, SysUserLoginResponse> {

    private SysUserBo sysUserBo;

    private String tokenValue;

    @Resource
    private SysRoleUserManager sysRoleUserManager;

    @Resource
    private SysUserManager sysUserManager;

    @Resource
    private SysRoleManager sysRoleManager;

    @Resource
    private CipherComponent cipherComponent;

    public UserLoginTrigger() {
        super(TriggerTypeEnum.USER_LOGIN);
    }

    @Override
    protected void before(TriggerContext<SysUserLoginRequest> triggerContext) {
        SysUserLoginRequest request = triggerContext.getTriggerRequest();
        // 校验登录参数
        validateOnLogin(request);
        // 重置参数值
        sysUserBo = null;
        tokenValue = null;

        // 根据用户账号查询数据库中的用户
        SysUserQuery sysUserQuery = new SysUserQuery();
        sysUserQuery.setLoginAccount(request.getLoginAccount());
        sysUserBo = sysUserManager.getOne(sysUserQuery);

        // 判断用户是否存在
        if (ObjectUtils.isEmpty(sysUserBo)) {
            throw new BusinessException(ExceptionCodeEnum.USER_NOT_EXIST);
        }

        // 验证密码
        String passwordEncrypt = cipherComponent.aesEncrypt(request.getPassword());
        if (!passwordEncrypt.equals(sysUserBo.getPassword())) {
            throw new BusinessException(ExceptionCodeEnum.USER_NOT_MATCH);
        }

        // 验证用户状态，是否被禁用
        if (!StatusEnum.ENABLE.equals(sysUserBo.getStatus())) {
            throw new BusinessException(ExceptionCodeEnum.USER_DISABLED);
        }
    }

    /**
     * 触发
     *
     * @param triggerContext 触发上下文
     * @return 触发结果
     */
    @Override
    @OLog(template = "用户登录：{#triggerContext.triggerRequest.loginAccount}登录", module = ModuleEnum.USER, actionType = ActionTypeEnum.LOGIN, actionIdEl = "{userId}")
    public SysUserLoginResponse trigger(TriggerContext<SysUserLoginRequest> triggerContext) {
        // 根据用户ID登录
        StpUtil.login(sysUserBo.getId());
        // 设置当前用户token信息
        tokenValue = StpUtil.getTokenValueByLoginId(sysUserBo.getId());

        LogRecordContext.put("userId", String.valueOf(sysUserBo.getId()));
        return new SysUserLoginResponse()
                .setToken(tokenValue)
                .setLoginAccount(sysUserBo.getLoginAccount())
                .setUsername(sysUserBo.getUsername())
                .setProfilePhoto(sysUserBo.getProfilePhoto())
                .setId(sysUserBo.getId());
    }

    @Override
    protected void after(TriggerContext<SysUserLoginRequest> triggerContext, SysUserLoginResponse triggerResponse) {
        // 查询角色信息并设置角色
        searchAndSetRoles();

        // 保存当前登录用户信息到 UserVO
        setUserInfo();

        // 设置用户拥有的角色列表
        triggerResponse.setRoles(sysUserBo.getRoles());
    }

    /**
     * 设置当前用户信息
     */
    private void setUserInfo() {
        UserVO userVO = new UserVO();
        userVO.setToken(tokenValue);
        userVO.setId(sysUserBo.getId());
        userVO.setLoginAccount(sysUserBo.getLoginAccount());
        userVO.setUsername(sysUserBo.getUsername());
        userVO.setPhone(sysUserBo.getPhone());
        userVO.setEmail(sysUserBo.getEmail());

        // 存在角色时，获取第一个角色
        if (CollUtil.isNotEmpty(sysUserBo.getRoles())) {
            userVO.setRoleId(sysUserBo.getRoles().get(0).getId());
        }

        UserUtil.set(userVO);
    }


    /**
     * 查询角色信息
     */
    private void searchAndSetRoles() {
        // 设置默认角色列表
        sysUserBo.setRoles(Collections.emptyList());
        // 查询角色信息
        SysRoleUserQuery sysRoleUserQuery = new SysRoleUserQuery();
        sysRoleUserQuery.setUserId(sysUserBo.getId());
        List<SysRoleUserBo> sysRoleUsers = sysRoleUserManager.list(sysRoleUserQuery);
        if (CollUtil.isNotEmpty(sysRoleUsers)) {
            List<Long> roleIds = sysRoleUsers.stream().map(SysRoleUserBo::getRoleId).toList();
            if (CollUtil.isNotEmpty(roleIds)) {
                List<SysRoleBo> sysRoles = sysRoleManager.listByPrimaryKeys(roleIds);
                if (CollUtil.isNotEmpty(sysRoles)) {
                    List<RoleVO> roleVos = sysRoles.stream()
                            .map(sysRole -> new RoleVO().setId(sysRole.getId())
                                    .setRoleName(sysRole.getRoleName())
                                    .setCode(sysRole.getCode())
                                    .setRemark(sysRole.getRemark()))
                            .toList();
                    sysUserBo.setRoles(roleVos);
                }
            }
        }
    }


    /**
     * 校验登录参数
     *
     * @param request 请求参数
     */
    private void validateOnLogin(SysUserLoginRequest request) {
        // 校验参数
        ValidatorChain validatorChain = new ValidatorChain();
        validatorChain.add(() -> new StrNotBlankValidator("loginAccount").validate(request::getLoginAccount));
        validatorChain.add(() -> new StrNotBlankValidator("password").validate(request::getPassword));
        ValidationResult validationResult = validatorChain.validate();
        // 参数校验失败
        if (!validationResult.isValid()) {
            throw ValidationException.message(validationResult.getErrorMessage());
        }
    }
}
